package com.hucsmn.stumansys.dao.impl;

import com.hucsmn.stumansys.dao.AdminDao;
import com.hucsmn.stumansys.entity.Admin;
import com.hucsmn.stumansys.utils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ColumnListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.sql.SQLException;
import java.util.List;

/**
 * AdminDao 的 MySQL 实现。
 * @author hucsmn
 */
public class AdminDaoImpl implements AdminDao {
    private static final Logger logger = LogManager.getLogger(AdminDaoImpl.class);

    @Override
    public boolean addAdmin(Admin admin) {
        boolean success = false;
        String sql = "INSERT INTO admin (name, crypt) VALUES (?, ?)";
        try {
            QueryRunner runner = new QueryRunner(DbUtils.getDataSource());
            Long maybeId = runner.insert(sql, new ScalarHandler<>(), admin.getName(), admin.getCrypt());
            if (maybeId != null && maybeId > 0 && maybeId <= Integer.MAX_VALUE) {
                success = true;
                admin.setId((int) (long) maybeId);
            } else {
                logger.error("addAdmin: invalid generated id " + maybeId);
            }
        } catch (SQLException e) {
            logger.error("addAdmin", e);
        }
        return success;
    }

    @Override
    public boolean removeAdmin(int id) {
        boolean success = false;
        String sql = "DELETE FROM admin WHERE id = ?";
        try {
            QueryRunner runner = new QueryRunner(DbUtils.getDataSource());
            int affected = runner.update(sql, id);
            success = affected == 1;
            if (!success) {
                logger.error("removeAdmin: affected " + affected + " rows");
            }
        } catch (SQLException e) {
            logger.error("removeAdmin", e);
        }
        return success;
    }

    @Override
    public boolean setAdmin(Admin admin) {
        boolean success = false;
        String sql = "UPDATE admin SET name = ?, crypt = ? WHERE id = ?";
        try {
            QueryRunner runner = new QueryRunner(DbUtils.getDataSource());
            int affected = runner.update(sql, admin.getName(), admin.getCrypt(), admin.getId());
            success = affected == 1;
            if (!success) {
                logger.error("setAdmin: affected " + affected + " rows");
            }
        } catch (SQLException e) {
            logger.error("setAdmin", e);
        }
        return success;
    }

    @Override
    public Admin getAdminByName(String name) {
        Admin admin = null;
        String sql = "SELECT id, name, crypt FROM admin WHERE name = ?";
        try {
            QueryRunner runner = new QueryRunner(DbUtils.getDataSource());
            admin = runner.query(sql, new BeanHandler<>(Admin.class), name);
        } catch (SQLException e) {
            logger.error("getAdminByName", e);
        }
        return admin;
    }

    @Override
    public boolean existsAdminName(String name) {
        boolean exists = false;
        String sql = "SELECT 1 FROM admin WHERE name = ?";
        try {
            QueryRunner runner = new QueryRunner(DbUtils.getDataSource());
            Object placeholder = runner.query(sql, new ScalarHandler<>(), name);
            exists = placeholder != null;
        } catch (SQLException e) {
            logger.error("existsAdminName", e);
        }
        return exists;
    }

    @Override
    public List<String> getAdminNames() {
        List<String> names = null;
        String sql = "SELECT name FROM admin ORDER BY name";
        try {
            QueryRunner runner = new QueryRunner(DbUtils.getDataSource());
            names = runner.query(sql, new ColumnListHandler<>());
        } catch (SQLException e) {
            logger.error("getAdminNames", e);
        }
        return names;
    }

    @Override
    public List<String> getAdminNamesLike(String prefix) {
        List<String> names = null;
        String sql = "SELECT name FROM admin WHERE name LIKE ? ESCAPE '!' ORDER BY name";
        String pattern = DbUtils.escapeLikePatternUseExclamation(prefix) + "%";
        try {
            QueryRunner runner = new QueryRunner(DbUtils.getDataSource());
            names = runner.query(sql, new ColumnListHandler<>(), pattern);
        } catch (SQLException e) {
            logger.error("getAdminNamesLike", e);
        }
        return names;
    }
}
